Steuern des Programmablaufs
In diesem Kapitel lernen Sie:
|
Wir haben bis jetzt im Großen und Ganzen nur Programme kennengelernt, die wie ein Uhrwerk ablaufen-vom Start zum Ende, und das nur einmal. In diesem Kapitel wollen wir Entscheidungs- und Kontrollstrukturen kennenlernen. Sie steuern ein Programm in Abhängigkeit davon, welche Ereignisse während des Programmlaufes auftreten.
Bedingtes Ausführen von Codeabschnitten
VBA-Programme können in ihnen enthaltene Bedingungen überprüfen und je nach Ergebnis der Prüfung unterschiedliche Operationen ausführen.
If...Then ("Wenn...Dann")
Diese Struktur führt die in ihr stehenden Anweisungen nur dann aus, wenn die Prüfung ein logisches "Wahr" (englisch "True") ergibt, wie im folgenden Beispiel:
Sub WennDann_1() If EinDatum <> Now Then EinDatum = Now End Sub
oder
Sub WennDann_2() If EinDatum < Now Then EinDatum = Now MsgBox "Das heutige Datum ist der " & EinDatum End If End Sub
Was ist der Unterschied? Bei der zweiten Version können Sie nach "If" beliebig viele Anweisungen schreiben, bei der ersten Version nur eine. Beachten Sie, daß die zweite Version am Ende mit der Anweisung "End If" abgeschlossen werden muß.
If...Then...ElseIf...Else...End If("Wenn...Dann...Sonst")
In dieser Struktur kann eine beliebige Anzahl verschiedener Bedingungen festgelegt werden. Die Bedingungen werden der Reihe nach geprüft. Trifft eine zu, werden die hinter ihr stehenden Anweisungen ausgeführt. Die folgenden Bedingungen werden nicht mehr geprüft.
Syntax
If Bedingung Then
Anweisungen...
ElseIf
AndereBedingung Then
Anweisungen...
ElseIf
WiederAndereBedingung Then
Anweisungen...
Else
Anweisungen...
End If
"Bedingung" ist immer ein logischer Vergleich, der den Wert "True" ergeben muß. Wird keine Bedingung erfüllt, werden die Anweisungen unterhalb von "Else" ausgeführt (wenn Sie dorthin keine Anweisungen setzen, funktioniert die Sache auch).
Beispiel
Sub WennDann_1() If EinDatum = Now Then EinDatum = Now End Sub Sub WennDann_2() If EinDatum < Now Then EinDatum = Now MsgBox "Das heutige Date ist der " & EinDatum End If End Sub
Hinweis Wenn "Bedingung" zwei Teilbedingungen enthält wie in
If (IsMissing(A) Or (A > 9))
werden beide Teilbedingungen geprüft, auch wenn schon die erste Teilbedingung "True" ergibt. Es müssen also immer beide Bedingungen prüfbar sein. Gibt es in unserem Beispiel die Variable "A" nicht, dann ist die Bedingung "IsMissing (A)" erfüllt; dennoch überprüft VBA auch die Bedingung "A > 9"-und unterbricht das Programm, weil es "A" nicht findet.
Ist es beim Erstellen des VBA-Programmes nicht klar, ob die Variable "A" zur Laufzeit vorhanden ist, müssen Sie also schreiben:
If IsMissing(A) Then Anweisungen... ElseIf A > 9 Then Anweisungen... End If
Wenn Sie mehr als ein, zwei Anweisungen angeben, ist es sinnvoller, sie legen die Anweisungen in eine eigene Prozedur:
If IsMissing(A) Then MeineProzedur ElseIf A > 9 Then MeineProzedur End If Sub MeineProzedur() Anweisungen... End Sub
Select Case
Im Gegensatz zu "If...Then...Else", wo Sie beliebig viele, sich auf ganz verschiedene Variable und Programmzustände beziehende Bedingungen angeben können, arbeitet "Select Case" mit nur einem einzigen "Testausdruck", dessen Wert Sie allerdings in beliebig vielen "Case"-Anweisungen untersuchen können. Sie können den Testausdruck auch einer Funktion zuweisen.
Syntax
Select Case Testausdruck
Case
Ausdrucksliste1
Anweisungen...
Case
Ausdrucksliste2
Anweisungen...
Case
Else
Anweisungen...
End Select
Beispiel
Sub PrüfeFall_1() Number = InputBox("Gib eine Zahl ein:") ' Variable initialisieren. Select Case Number ' Zahl auswerten. Case 1 To 5 ' Zahl im Bereich von 1 bis 5. TestZeichenF = "im Bereich von 1 To 5" Case 6, 7, 8, 9, 10 ' Zahl im Bereich von 6 bis 10. TestZeichenF = "im Bereich von 6 To 10" Case MeineFunktion(Number) TestZeichenF = "Funktion <<MeineFunktion>> ausgeführt" Case Else ' andere Werte. TestZeichenF = "nicht im Bereich von 1 bis 10" End Select MsgBox "Die Zahl liegt " & TestZeichenF End Sub Function MeineFunktion(x) MsgBox "Bin in <<MeineFunktion>>" End Function
Mehrfaches Ausführen desselben Codes mit Programmschleifen
Dies geschieht mit Hilfe von Schleifenstrukturen, von denen VBA drei kennt. Die Anweisungen zwischen dem Kopf und dem Fuß der Schleife werden solange ausgeführt, bis die "Schleifenbedingung" nicht mehr zutrifft.
Do While...Loop
Wiederholt einen Block mit Anweisungen, solange eine Bedingung "Wahr" (englisch "True") ist, oder bis die Bedingung "True" wird. Setzen Sie diese Schleife ein, wenn Sie beim Programmieren nicht wissen können, wie oft die Anweisungen in der Schleife zur Laufzeit des VBA-Programmes ausgeführt werden müssen.
Syntax 1
Do [{While | Until} Bedingung]
[Anweisungen]
[Exit
Do]
[Anweisungen]
Loop
Syntax 2
Do
[Anweisungen]
[Exit Do]
[Anweisungen]
Loop
[{While | Until}Bedingung]
Elemente
Bedingung ein Ausdruck, der entweder Wahr oder Falsch ist.
Anweisungen eine oder mehrere Anweisungen, die wiederholt werden, bis Bedingung Wahr wird.
Exit Do verläßt die Kontrollstuktur vom Typ Do...Loop "vorzeitig", also wenn "Bedingung" noch zutrifft. Exit Do läßt sich an beliebiger Stelle und beliebig oft in einer solchen Struktur verwenden. Diese Anweisung wird oft in Zusammenhang mit der Auswertung einer Bedingung (zum Beispiel If...Then) eingesetzt und setzt die Ausführung mit der ersten Anweisung im Anschluß an die Schleife fort. In verschachtelten Do...Loop übergibt Exit Do die Steuerung an die Schleife der nächst-niedrigeren Verschachtelungsstufe.
KOPFGESTEUERTE "DURCHLAUFE"-SCHLEIFE
Bei dieser Form der "Do"-Schleife wird "Bedingung" schon geprüft, bevor die Schleife auch nur ein einziges Mal durchlaufen worden ist. Ist "Bedingung" schon vor dem ersten Durchlauf "False", werden die Anweisungen kein einziges Mal ausgeführt; dasProgramm setzt in der Zeile nach "Loop" fort.
Beispiel
Sub DurchlaufeKopf_1() LangeZeichenfolge = "Ich bin eine lange Zeichenfolge" KurzeZeichenfolge = "i" MsgBox ZeichenfolgenAnzahl(LangeZeichenfolge, _ KurzeZeichenfolge) End Sub Function ZeichenfolgenAnzahl(LangeZnF, SuchZnF) Position = 1 Do While InStr(Position, LangeZnF, SuchZnF) Position = InStr(Position, LangeZnF, SuchZnF) + 1 Count = Count + 1 Loop ZeichenfolgenAnzahl = Count End Function
Die hier beschriebene Funktion sucht in einer Zeichenkette ("LangeZnF") nach einer zweiten Zeichenkette ("SuchZnF") und zählt, wie oft diese gefunden wurde. Wird die zweite Zeichenkette kein einziges Mal gefunden, dann ergibt die Bedingung "InStr(Position; LangeZnF; SuchZnF)" den Wert 0. Dies übersetzt VBA in "False"; die Schleife wird kein einziges Mal durchlaufen. Jede andere Zahl wird mit "True" übersetzt, die Schleife wird durchlaufen.
FUSSGESTEUERTE "DO"-SCHLEIFE
Bei dieser Form der Schleife werden die in der Schleife gegebenen Anweisungen zunächst ausgeführt, erst dann wird die am Ende der Schleife definierte Schleifenbedingung geprüft. Diese Form der "Durchlaufe"-Schleife verwenden Sie immer dann, wenn Sie sicher sind, daß die Anweisungen zumindest einmal ausgeführt werden müssen
Sub Durchlaufe_Fuß() Do BenutzerdatenVerarbeiten Antwort = MsgBox("Weitere Daten verarbeiten?", vbYesNo) Loop While Antwort = vbYes End Sub Sub BenutzerdatenVerarbeiten() MsgBox "Bin in BenutzerdatenVerarbeiten" End Sub
AUSFÜHREN, SOLANGE EINE BEDINGUNG FALSCH IST
Die beiden gerade gezeigten "Do"-Schleifen werden solange abgearbeitet, solange die Schleifenbedingung "True" ergibt. Mit Hilfe des Befehlswortes "BisWahr" können Sie aber auch "Durchlaufe"-Schleifen bilden, die solange durchlaufen werden, solange die Bedingung "Falsch" ergibt.
Sub Durchlaufe_Fuß() Do BenutzerdatenVerarbeiten Antwort = MsgBox("Weitere Daten verarbeiten?", vbYesNo) Loop Until Antwort = vbNo End Sub Sub BenutzerdatenVerarbeiten() MsgBox "Bin in BenutzerdatenVerarbeiten" End Sub
For...Next
Diese Art der Schleife sollten Sie immer dann verwenden, wenn die Zahl der Durchläufe zumindest während des Programmlaufes vor Eintritt in den Schleifencode feststeht. Sie wiederholt solange eine Reihe von Anweisungen, bis der Schleifenzähler einen bestimmten Wert erreicht.
Syntax
For Zähler = Anfang To Ende [Step Schritt]
[Anweisungen]
[Exit For]
[Anweisungen]
Next [Zähler]
Elemente
Die For...Next-Anweisung verwendet die folgenden Argumente:
Zähler Numerische Variable, die als Schleifenzähler dient. Ein Element eines Datenfelds oder eines benutzerdefinierten Typs ist an dieser Stelle nicht zulässig.
Anfang Startwert von Zähler.
Ende Endwert von Zähler.
Schritt Schrittweite, um die Zähler bei jedem Schleifendurchlauf verändert wird. Diese Angabe ist optional; wenn Sie sie weglassen, nimmt VBA als Schrittweite +1 an. Bitte beachten Sie, daß bei Schrittweiten, die Nachkommastellen enthalten, Rundungsfehler auftreten können!
Anweisungen Eine oder mehrere Anweisungen zwischen For und Next, die mehrmals ausgeführt werden.
Negative Schrittweite
Wenn "Ende" größer ist als "Anfang", dann müssen Sie "Schritt" angeben. Die Schleife wird sonst kein einziges Mal durchlaufen!
Anmerkungen
Nachdem im ersten Schleifendurchlauf alle Anweisungen ausgeführt wurden, addiert das Programm Schritt zum Wert von Zähler hinzu und führt denselben Test durch wie zu Beginn des ersten Durchlaufs. Wenn der Endwert noch nicht überschritten (bzw. bei negativem Schritt unterschritten) wurde, führt das Programm die Schleife erneut aus, ansonsten setzt es die Ausführung mit der Anweisung fort, die auf die Next-Anweisung folgt.
Beachten Sie, daß Zähler nach dem Verlassen der Schleife nicht den Wert von Ende hat, sondern von Ende+Schritt beziehungsweise Ende-Schritt.
Schleife mit "Exit For" vorzeitig verlassen
Exit For führt zum sofortigen Verlassen der Schleife, auch wenn "Ende" noch nicht erreicht worden ist. Es läßt sich an beliebigen Stellen und beliebig oft in der Schleife verwenden. Exit For wird oft in Zusammenhang mit der Auswertung einer Bedingung (zum Beispiel If...Then) eingesetzt und weist das Programm an, die Ausführung mit der ersten Anweisung hinter Next fortzusetzen.
Mehrere Schleifen ineinander
Sie können For...Next-Schleifen verschachteln, indem Sie eine dieser Schleifen innerhalb einer anderen verwenden. Die Zähler für alle Schleifen müssen dabei jedoch durch verschiedene Variablennamen dargestellt werden, wie im folgenden Beispiel:
For I = 1 To 10 For J = 1 To 10 For K = 1 To 10 . . . Next K Next J Next I
Hinweis Das Argument Element (z.B. "Next K") in der Next-Anweisung ist nicht zwingend notwendig. Die Ausführung wird mit einem Element genauso fortgesetzt wie ohne Element. Eine Next-Anweisung vor der zugehörigen For-Anweisung führt zu einem Fehler.
For Each...Next
Eine hochinteressante Schleife, so richtig auf VBA zugeschniten. Sie arbeitet nämlich nicht mit Wahrheitswerten oder Zählern, sondern mit Objekten. Genauer gesagt, mit all jenen Objekten, die Auflistungen enthalten. Wieviele Elemente die Auflistung hat, brauchen Sie gar nicht zu wissen.
Syntax
For Each Element In Gruppe
[Anweisungen]
[Exit
For]
[Anweisungen]
Next [Element]
Die Anweisung For Each...Next verwendet die folgenden Argumente:
Argument | Beschreibung |
Element | Variable zum Durchlauf durch die Elemente einer Auflistung oder eines Datenfeldes. Bei Auflistungen sind für Element nur Variant-Variablen, allgemeine Variablen vom Typ Objekt oder spezielle Objektvariablen für die OLE-Automatisierung zulässig. Bei Datenfeldern sind für Element nur Variant-Variablen zulässig. |
Gruppe | Name einer Auflistung von Objekten oder eines Datenfeldes (abgesehen von Datenfeldern mit einem benutzerdefinierten Typ). |
Anweisungen | Eine oder mehrere Anweisungen, die für jedes Element in Gruppe ausgeführt werden. |
Wichtig Wenn Sie For Each...Next mit Datenfeldern verwenden, können Sie den Wert der Datenfeldelemente, die durch die Kontrollvariable Element bestimmt werden, nur lesen. Es ist nicht möglich, den Wert zu ändern, indem Sie Element einen Wert zuweisen.
Beispiel Angenommen, Sie wollen alle offenen Arbeitsmappen schließen, ausgenommen die eine, die Ihr Programm enthält. Alle Arbeitsmappen sind in dem Container-Objekt "Workbooks" enhalten-egal, wieviele es sind und wie sie heißen. Wir können dann schreiben:
Sub FürAlle_1() For Each EineMappe In Workbooks If EineMappe.Name <> ThisWorkbook.Name Then EineMappe.Close Next End Sub
Zweites Beispiel: Wir wollen alle Zellen in einem mit der Maus markierten Bereich fett schreiben, deren Wert größer als 1000 ist:
Sub FürAlle_2() For Each EineZelle In Selection Wenn EineZelle.Value > 1000 Then EineZelle.Font.Bold = True End If Next End Sub
EINSATZ IN DATENFELDERN
For Each...Next können Sie auch verwenden, um Datenfelder zu bearbeiten:
Sub FürAlle_InDatenfeldern_1() Dim MeinDatenfeld(9) As Variant For Zähler = 0 To 9 MeinDatenfeld(Zähler) = Zähler Next For Each EinElement In MeinDatenfeld MsgBox "Aktuelles Element hat den Wert: " & _ EinElement Next End Sub
Falls das Datenfeld mehr als eine Element-Dimension hat:
' In einem Datenfeld mit mehr als einer Dimension ' ist die "For Each"-Schleife nicht sinnvoll Sub FürAlle_InDatenfeldern_2() Dim MeinDatenfeld(9, 1) As Variant For Zähler = 0 To 9 MeinDatenfeld(Zähler, 1) = Zähler Next For Each EinElement In MeinDatenfeld MsgBox "Aktuelles Element hat den Wert: " & _ EinElement Next End Sub
Wenn Sie diesen Code laufen lassen, werden Sie merken, daß die "For Each"-Schleife alle 20 Elemente des Datenfeldes durchläuft. Sie ist also in diesem Fall nicht brauchbar. Verwenden Sie stattdessen eine "For"-Schleife:
' Sie verwenden also besser eine "For"-Schleife Sub Für_InDatenfeldern_1() Dim MeinDatenfeld(9, 1) As Variant For Zähler = 0 To 9 MeinDatenfeld(Zähler, 1) = Zähler Next For Schleifenzähler = LBound(MeinDatenfeld) To _ UBound(MeinDatenfeld) MsgBox "Aktuelles Element hat den Wert: " & _ MeinDatenfeld(Schleifenzähler, 1) Next End Sub
Schleifen vorzeitig verlassen
Wenn eine Schleife ihren Dienst verrichtet hat, bevor die Schleifenbedingung erfüllt oder der Endstand eines Zählers überschritten worden ist, können Sie das Ausführen der Anweisungen in der Schleife mit Hilfe einer der "Exit"-Anweisungen beenden.
Exit Do
Exit For
brechen jeweils die in ihren Namen enthaltene Schleifenstruktur ab. Für das Verlassen von Prozeduren und Funktionen gibt es ähnliche Anweisungen:
Exit Sub
Exit Function
Beispiel
Der nachfolgende Code verwendet "Exit"-Anweisungen, um eine For...Next-Schleife, eine Do...Loop-Schleife und eine Sub-Prozedur zu verlassen.
Sub ExitAnweisungDemo() Do ' Endlosschleife. For I = 1 To 1000 ' 1000 Durchläufe. TestNum = Int(Rnd * 1000) ' Zufallszahl generieren. Select Case TestNum ' Zufallszahl auswerten. Case 7: Exit For ' Wenn 7, For...Next beenden. Case 29: Exit Do ' Wenn 29, Do...Loop beenden. Case 54: Exit Sub ' Wenn 54, Sub-Prozedur beenden. End Select Next I Loop End Sub
Automatisches Ablaufen von Programmen
Beim Laden einer Arbeitsmappe
Wenn Sie eine Arbeitsmappe laden, dann untersucht EXCEL, ob es in dieser Mappe eine VBA-Prozedur mit dem Namen "auto_öffnen" gibt. Wird sie gefunden, dann werden die in ihr enthaltenen Anweisungen automatisch abgearbeitet. Gleichermassen werden Anweisungen einer Prozedur mit dem Namen "auto_schliessen" automatisch beim Schliessen einer Arbeitsmappe durchgeführt.
Beispiele für die in diesem Abschnitt behandelten Anweisungen finden sich in der Datei "REISEN96.xls" im Modulblatt "Anfang". |
Sub auto_öffnen() ...Anweisungen End Sub Sub auto_schliessen() ...Anweisungen End Sub
Hinweis Es kann pro Arbeitsmappe nur eine "auto_öffnen"- und eine "auto_schliessen"-Prozedur geben. Wird eine Arbeitsmappe durch VBA-Code geladen, werden die "auto"-Prozeduren nicht automatisch ausgeführt. Sie müssen mit Hilfe der "RunAutoMacros"-Methode aufgerufen werden:
In diesem Beispiel wird die Arbeitsmappe ANALYSE.XLS geöffnet und der "Auto-Open"-Makro ausgeführt.
Workbooks.Open "ANALYSE.XLS" ActiveWorkbook.RunAutoMacros xlAutoOpen
In diesem Beispiel wird der Makro "Auto_Close" für die aktive Arbeitsmappe ausgeführt und die Arbeitsmappe geschlossen.
With ActiveWorkbook .RunAutoMacros xlAutoClose .Close End With
Beim Aktivieren und Verlassen eines Tabellenblattes
EXCEL läßt es zu, daß ein VBA-Programm automatisch gestartet wird, sobald ein neues Blatt in den Vordergrund geholt wird. Die Anweisung dafür lautet:
Application.OnSheetActivate = ActiveWorkbook.Name & _ "!Modul1.Meine_Aktivieren_Sub"
In diesem Beispiel wird der OnSheetActivate-Eigenschaft der Makro "Meine_Aktivieren_Sub" in Modul1 der aktiven Arbeitsmappe zugeordnet. Dieser Makro wird jedesmal ausgeführt, wenn der Benutzer ein Tabellenblatt in einer beliebigen Arbeitsmappe aktiviert.
In diesem Beispiel wird der OnSheetActivate-Makro entfernt.
Application.OnSheetActivate = ""
So allgemein wird die "OnSheetActivate"-Eigenschaft wohl kaum nützlich sein. Sie finden in der Datei "REISEN96.xls" ein lebensnäheres. Dort geht es darum, daß in einem Arbeitsblatt Nullen angezeigt werden müssen, in einem zweiten aber nicht angezeigt werden dürfen. Jedesmal, wenn zu einem anderen Blatt gewechselt wird, läuft der "OnSheetActivate"-Makro automatisch ab-er prüft dabei, ob es sich um eines der beiden Blätter aus "REISEN96.xls" handelt. Falls nicht, stellt er seine Arbeit gleich wieder ein.
'Sub Nullenanzeige() ' In der Tabelle "Reisedaten" muß die Uhrzeit "00:00" angezeigt werden ' können. Diese Uhrzeit entspricht dem Datum 1.1.1900, 00 Uhr, und ' wird durch die Zahl "0" repräsentiert. ' In diesem Blatt müssen daher Nullen angezeigt werden. ' In der Tabelle "SummenTabelle" stören dagegen die Nullen. ' Daher wird bei der Anzeige dieser Tabelle die Nullen-Anzeige ausgeschaltet. Sub Nullenanzeige() ' OnSheetActivate ist global (für jede geöffnete Mappe) wirksam. ' Daher müssen wir prüfen, ob diese Arbeitsmappe aktiv ist. If ActiveWorkbook.Name <> ThisWorkbook.Name Then Exit Sub If ActiveSheet.Name = "Reisedaten" Then ActiveWindow.DisplayZeros = True Call AlleBeschriebenenSpaltenZeigen ElseIf ActiveSheet.Name = "SummenTabelle" Then ActiveWindow.DisplayZeros = False Call AlleBeschriebenenSpaltenZeigen End If End Sub
Soll ein VBA-Programm beim Verlassen eines Blattes ausgeführt werden, so müssen Sie der "OnSheetDeactivate"-Eigenschaft den Namen einer VBA-Prozedur angeben, die dann jedesmal, wenn Sie von einem Blatt in ein anderes wechseln, ausgeführt wird.
Copyright © by JOANNEUM RESEARCH Forschungsgesellschaft mbH |